package com.nlx.notes.module.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nlx.notes.module.bean.dto.FlowPageQueryDTO;
import com.nlx.notes.module.bean.dto.FlowSaveDTO;
import com.nlx.notes.module.bean.dto.flow.UpdateDBAmountDTO;
import com.nlx.notes.module.bean.dto.querydb.FlowDayQueryDbDTO;
import com.nlx.notes.module.core.consts.GlobalConst;
import com.nlx.notes.module.core.enums.TransactionTypeEnum;
import com.nlx.notes.module.core.util.AmountConverterUtils;
import com.nlx.notes.module.core.util.DateUtils;
import com.nlx.notes.module.entity.FlowDayStatistics;
import com.nlx.notes.module.mapper.FlowDayStatisticsMapper;
import com.nlx.notes.module.service.IFlowDayStatisticsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author nlx
 * @since 2024-12-15
 */
@Service
public class FlowDayStatisticsServiceImpl extends ServiceImpl<FlowDayStatisticsMapper, FlowDayStatistics> implements IFlowDayStatisticsService {

    @Override
    public FlowDayStatistics findByDay(String date,Long userId,Long bookId) {
        if(StrUtil.isEmpty(date)){
            return null;
        }

        return getBaseMapper().selectOne(Wrappers.lambdaQuery(FlowDayStatistics.class)
                .eq(FlowDayStatistics::getUserId,userId)
                .eq(FlowDayStatistics::getBookId,bookId)
                .eq(FlowDayStatistics::getDayTime,date)
                .eq(FlowDayStatistics::getDelFlag,0),false);
    }

    @Override
    public IPage<FlowDayStatistics> findByCondition(FlowPageQueryDTO flowPageQueryDTO) {
        String starDate = flowPageQueryDTO.getStartDate();
        String endDate = flowPageQueryDTO.getEndDate();
        String transactionType = flowPageQueryDTO.getTransactionType();
        IPage<FlowDayStatistics> page = new Page<>(flowPageQueryDTO.getPage(),flowPageQueryDTO.getPageSize());

        return this.getBaseMapper().selectPage(page, Wrappers.lambdaQuery(FlowDayStatistics.class)
                .ge(FlowDayStatistics::getDayTime, starDate)
                .le(FlowDayStatistics::getDayTime, endDate)
                .eq(FlowDayStatistics::getTransactionType, transactionType)
                .eq(FlowDayStatistics::getDelFlag, 0));
    }

    @Override
    public List<FlowDayStatistics> findInDay(Set<String> dayTimes,Long bookId,Long userId) {
        return this.getBaseMapper().selectList(Wrappers.lambdaQuery(FlowDayStatistics.class)
                .eq(FlowDayStatistics::getUserId,userId)
                .eq(FlowDayStatistics::getBookId,bookId)
                .in(FlowDayStatistics::getDayTime,dayTimes)
                .orderByDesc(FlowDayStatistics::getDayTime));
    }

    @Override
    public void saveDayFlow(FlowSaveDTO flowSaveDTO) {
        String day = DateUtils.formatDate(flowSaveDTO.getTransactionDate());
        int amount = AmountConverterUtils.convertYuanToFen(flowSaveDTO.getAmount());
        FlowDayStatistics statistics = this.findOneByDay(day,flowSaveDTO.getUserId());
        if(null == statistics){
            FlowDayStatistics flowDayStatistics = new  FlowDayStatistics();
            if(TransactionTypeEnum.INCOME.getCode().equalsIgnoreCase(flowSaveDTO.getTransactionType())){
                flowDayStatistics.setIncome(amount);
            }else{
                flowDayStatistics.setExpense(amount);
            }
            flowDayStatistics.setTransactionType(flowSaveDTO.getTransactionType());
            flowDayStatistics.setDayTime(day);
            flowDayStatistics.setUserId(flowSaveDTO.getUserId());
            flowDayStatistics.setDelFlag(0);
            this.save(flowDayStatistics);
        }else{
            this.incDayAmount(statistics.getId(),amount,flowSaveDTO.getTransactionType());
        }


    }

    private void incDayAmount(Long id, int amount,String transactionType) {
        if(id == null || 0 == amount){
            return ;
        }
        if(TransactionTypeEnum.INCOME.getCode().equalsIgnoreCase(transactionType)){
            this.getBaseMapper().incDayIncomeAmount(id,amount);
        }else{
            this.getBaseMapper().incDayExpenseAmount(id,amount);
        }
    }


    /**
     * 通过年份查询数据
     * @param date 日期
     * @param userId 用户
     * @return FlowYearStatistics
     */
    private FlowDayStatistics findOneByDay(String date,Long userId) {
        if(null == date || null == userId){
            return null;
        }
        return this.getBaseMapper().selectOne(Wrappers.lambdaQuery(FlowDayStatistics.class)
                .eq(FlowDayStatistics::getUserId,userId)
                .eq(FlowDayStatistics::getDayTime,date)
                .eq(FlowDayStatistics::getDelFlag,0)
                .last(" limit 1"));
    }

    @Override
    public Map<String, FlowDayStatistics> findDayMapByDays(Set<String> dayTimes,Long bookId,Long userId) {
        List<FlowDayStatistics> dayStatistics = this.findInDay(dayTimes,bookId,userId);
        if(CollUtil.isEmpty(dayStatistics)){
            return Collections.emptyMap();
        }
        return dayStatistics.stream()
                .collect(Collectors.toMap(
                        FlowDayStatistics::getDayTime,
                        day -> day,
                        (existing, replacement) -> replacement // 冲突时保留替换值
                ));
    }

    @Override
    public void deleteFlow(UpdateDBAmountDTO updateDBAmountDTO) {
        String day = DateUtils.formatDate(updateDBAmountDTO.getDate());
        FlowDayStatistics flowDayStatistics = this.findByDayAndType(day,updateDBAmountDTO.getUserId());
        if(null == flowDayStatistics){
            return ;
        }
        updateDBAmountDTO.setId(flowDayStatistics.getId());
        //通过天查询数据
        incDayAmount(flowDayStatistics.getId(),updateDBAmountDTO.getAmount(),updateDBAmountDTO.getTransactionType());
//        this.getBaseMapper().decDayAmount(flowDayStatistics.getId(),updateDBAmountDTO.getAmount());
    }

    @Override
    public List<FlowDayStatistics> findListByCondition(FlowDayQueryDbDTO flowDayQueryDbDTO) {
        if(null == flowDayQueryDbDTO.getUserId()){
            return null;
        }
        return this.getBaseMapper().selectList(Wrappers.lambdaQuery(FlowDayStatistics.class)
                .eq(FlowDayStatistics::getUserId,flowDayQueryDbDTO.getUserId())
                .eq(FlowDayStatistics::getBookId,flowDayQueryDbDTO.getBookId())
                .ge(FlowDayStatistics::getDayTime,flowDayQueryDbDTO.getStartDate())
                .le(FlowDayStatistics::getDayTime,flowDayQueryDbDTO.getEndDate())
                .eq(FlowDayStatistics::getDelFlag, GlobalConst.DEL_FLAG_NORMAL).orderByAsc(FlowDayStatistics::getDayTime));
    }

    private FlowDayStatistics findByDayAndType(String date, Long userId) {
        if(StrUtil.isEmpty(date) || null == userId ){
            return null;
        }
        return this.getBaseMapper().selectOne(Wrappers.lambdaQuery(FlowDayStatistics.class)
                .eq(FlowDayStatistics::getUserId,userId)
                .eq(FlowDayStatistics::getDayTime,date)
                .eq(FlowDayStatistics::getDelFlag,0).last(" limit 1"));
    }
}
